/* eslint-disable no-case-declarations */

/* eslint-disable no-param-reassign */

/**
 * 简洁模板语法规则
 */
var artRule = {
  test: /{{([@#]?)[ \t]*(\/?)([\w\W]*?)[ \t]*}}/,
  use: function use(match, raw, close, code) {
    var compiler = this;
    var options = compiler.options;
    var esTokens = compiler.getEsTokens(code);
    var values = esTokens.map(function (token) {
      return token.value;
    });
    var result = {};
    var group;
    var output = raw ? 'raw' : false;
    var key = close + values.shift(); // 旧版语法升级提示

    var warn = function warn(oldSyntax, newSyntax) {
      console.warn("".concat(options.filename || 'anonymous', ":").concat(match.line + 1, ":").concat(match.start + 1, "\n") + "Template upgrade: {{".concat(oldSyntax, "}} -> {{").concat(newSyntax, "}}"));
    }; // v3 compat: #value


    if (raw === '#') {
      warn('#value', '@value');
    }

    switch (key) {
      case 'set':
        code = "var ".concat(values.join('').trim());
        break;

      case 'if':
        code = "if(".concat(values.join('').trim(), "){");
        break;

      case 'else':
        var indexIf = values.indexOf('if'); // eslint-disable-next-line no-bitwise

        if (~indexIf) {
          values.splice(0, indexIf + 1);
          code = "}else if(".concat(values.join('').trim(), "){");
        } else {
          code = "}else{";
        }

        break;

      case '/if':
        code = '}';
        break;

      case 'each':
        group = artRule._split(esTokens);
        group.shift();

        if (group[1] === 'as') {
          // ... v3 compat ...
          warn('each object as value index', 'each object value index');
          group.splice(1, 1);
        }

        var object = group[0] || '$data';
        var value = group[1] || '$value';
        var index = group[2] || '$index';
        code = "$each(".concat(object, ",function(").concat(value, ",").concat(index, "){");
        break;

      case '/each':
        code = '})';
        break;

      case 'block':
        group = artRule._split(esTokens);
        group.shift();
        code = "block(".concat(group.join(',').trim(), ",function(){");
        break;

      case '/block':
        code = '})';
        break;

      case 'echo':
        key = 'print';
        warn('echo value', 'value');
        break;

      case 'print':
      case 'include':
      case 'extend':
        if (values.join('').trim().indexOf('(') !== 0) {
          // 执行函数省略 `()` 与 `,`
          group = artRule._split(esTokens);
          group.shift();
          code = "".concat(key, "(").concat(group.join(','), ")");
          break;
        }

        break;

      default:
        // eslint-disable-next-line no-bitwise
        if (~values.indexOf('|')) {
          var v3split = ':'; // ... v3 compat ...
          // 将过滤器解析成二维数组

          var _group = esTokens.reduce(function (group_, token) {
            var _value = token._value,
                type = token.type;

            if (_value === '|') {
              group_.push([]);
            } else if (type !== "whitespace" && type !== "comment") {
              if (!group_.length) {
                group_.push([]);
              }

              if (_value === v3split && group_[group_.length - 1].length === 1) {
                warn('value | filter: argv', 'value | filter argv');
              } else {
                group_[group_.length - 1].push(token);
              }
            }

            return group_;
          }, []).map(function (g) {
            return artRule._split(g);
          }); // 将过滤器管道化


          code = _group.reduce(function (accumulator, filter) {
            var name = filter.shift();
            filter.unshift(accumulator);
            return "$imports.".concat(name, "(").concat(filter.join(','), ")");
          }, _group.shift().join(" ").trim());
        }

        output = output || 'escape';
    }

    result.code = code;
    result.output = output;
    return result;
  },
  // 将多个 javascript 表达式拆分成组
  // 支持基本运算、三元表达式、取值、运行函数，不支持 `typeof value` 操作
  // 只支持 string、number、boolean、null、undefined 这几种类型声明，不支持 function、object、array
  _split: function _split(esTokens) {
    esTokens = esTokens.filter(function (_ref) {
      var type = _ref.type;
      return type !== "whitespace" && type !== "comment";
    });
    var current = 0;
    var lastToken = esTokens.shift();
    var punctuator = "punctuator";
    var close = /\]|\)/;
    var group = [[lastToken]];

    while (current < esTokens.length) {
      var esToken = esTokens[current];

      if (esToken.type === punctuator || lastToken.type === punctuator && !close.test(lastToken.value)) {
        group[group.length - 1].push(esToken);
      } else {
        group.push([esToken]);
      }

      lastToken = esToken;
      current++;
    }

    return group.map(function (g) {
      return g.map(function (_g) {
        return _g.value;
      }).join("");
    });
  }
};
export default artRule;